package club.pinea.server;

import club.pinea.constants.GameConfigConstants;
import club.pinea.mapper.RoomMapper;
import club.pinea.model.PoolScore;
import club.pinea.model.Room;
import club.pinea.model.Seat;
import club.pinea.utils.RedisCache;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.CollectionUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

import static club.pinea.constants.RedisPrefix.*;

/**
 * @author pineapple
 * @date 2017年12月26日 下午1:29:36
 * @description 服务器端
 */
@Configuration
public class GameServer implements Runnable {

    Logger logger = LoggerFactory.getLogger(GameServer.class);

    @Autowired
    private GameServerInitializer gameServerInitializer;

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private RedisCache redisCache;

    @javax.annotation.Resource
    private RoomMapper roomMapper;

    @Value("${server.lobby.maxSeatNum}")
    public Integer maxSeatNum;

    @Value("${server.lobby.maxRoomNum}")
    public Integer maxRoomNum;

    /**
     * 端口号
     */
    @Value("${server.game.port}")
    public Integer gamePort;

    /**
     * 初始化房间信息（根据数据库来）
     */
    public void initLobbySeats() {
        List<Room> rooms = roomMapper.queryAll(new Room());
        if (!CollectionUtils.isEmpty(rooms)) {
            rooms.forEach(r -> {
                // 先清除信息，再重新设置
                redisCache.deleteObject(ROOM_SEAT_PREFIX + r.getRoomId());
                for (int i = 0; i < r.getSeatCount(); i++) {
                    Seat seat = new Seat(i);
                    seat.setMultiplyPower(r.getMultiplyPower());
                    redisCache.rPush(ROOM_SEAT_PREFIX + r.getRoomId(), seat);
                }
            });
        }
    }

    /**
     * 初始化卡牌信息
     */
    public void initGameCards() {
        Resource resource = resourceLoader.getResource("classpath:cardJson.json");
        BufferedReader reader;
        String cardJson = "";
        try {
            resource.getInputStream();
            //解析文件中的json字符串
            reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
            while (reader.ready()) {
                cardJson += reader.readLine();
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //将json字符串转换为json对象，并存储到缓存中
        JSONObject obj = JSONObject.parseObject(cardJson);
        JSONArray arr = obj.getJSONArray("cards");

        redisCache.setCacheList(GAME_CARD_KEY, arr);

        List<Room> rooms = roomMapper.queryAll(new Room());

        rooms.forEach(r -> {
            redisCache.deleteObject(GAME_POOL_SCORE_PREFIX + r.getRoomId());
            for (int i = 0; i < r.getSeatCount(); i++) {
                PoolScore poolScore = new PoolScore();
                poolScore.set_4K(GameConfigConstants.min_4K);
                poolScore.set_SF(GameConfigConstants.min_SF);
                poolScore.set_RS(GameConfigConstants.min_RS);
                poolScore.set_5K(GameConfigConstants.min_5K);
                redisCache.rPush(GAME_POOL_SCORE_PREFIX + r.getRoomId(), poolScore);
            }
        });
    }

    /**
     * 创建服务端线程组并绑定端口
     *
     * @throws Exception
     */
    @Override
    public void run() {
        // 初始化卡池
        this.initGameCards();
        // 初始化大厅座位
        this.initLobbySeats();

        //用于监测客户端连接的线程池
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //工作的线程池
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            //将两个线程组绑定到引导程序并添加参数
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new LoggingHandler(LogLevel.DEBUG))
                    .childHandler(gameServerInitializer);
            //绑定端口, 同步等待成功;
            ChannelFuture future = bootstrap.bind(gamePort).sync();
            logger.info("游戏服务器启动成功，端口：" + gamePort);
            //等待服务端监听端口关闭
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //优雅关闭 线程组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}
